/**
 * @created by helin3 on 2017-11-25
 * @updated by
 * @description 服务访问组件
 */
(function (yufp, window, factory) {
  var exports = factory(yufp, window, window.document);
  if (typeof define === 'function') {
    define(exports);
  }
  window.yufp.service = exports;
}(yufp, window, function (yufp, window, document) {
  var DEFAUT_OPTION = {
    fullscreen: true, // 遮罩是否全屏
    lock: true, // 在使用全屏遮罩时，控制是否锁定屏幕的滚动，true: 锁定，false: 不锁定
    body: false // 遮罩是否插入至 DOM 中的 body 中，true: 插入，false: 不插入
  };
  /**
   * 定义Service
   * @constructor
   */
  function Service () {
    this.options = {
      method: 'POST', // 默认POST，支持4种访问类型 GET/POST/PUT/DELETE
      async: true, // 异步请求
      data: {}, // 请求数据
      headers: {
        'Content-Type': 'application/json; charset=UTF-8'
        // 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
      }, // http请求头
      dataType: 'json', // 默认返回数据类型
      timeout: 90000, // 默认超时时间
      cache: false, // 是否缓存
      needToken: true, // 是否传认证Token值去后台
      callback: false, // 回调方法
      loadingUi: {
        // 是否展示加载loading
        show: false,
        // 局部loading 作用的/覆盖的 DOM 对象，
        // 如果不配置，则显示全局loading
        target: null,
        // loading的自定义option
        option: null
      }
    };
    this._filters = []; // 过滤器集合
    this.basePath = ''; // 应用名
    this.tokenId = 'Authorization'; // TOKEN 名
    this.tokenVal = ''; // TOKEN 值
    this.storage = window.YUFP_SYS_CONFIG.debugModel ? yufp.localStorage : yufp.sessionStorage; // 根据debug模式，存储会话值
  }
	
 /**
   * 获取拓展请求头
   */
  Service.prototype.getExtendHeader = function () {
    return {
      'currentUserId': yufp.session.user && yufp.session.user.loginCode,
      'currentUserOrgId': yufp.session.org && yufp.session.org.code
    };
  };
  /**
   * 发送请求
   * @param options
   */
  Service.prototype.request = function (options) {
    var _this = this;
    var option;
    var _options = yufp.extend({}, _this.options, options);
    if (_options.loadingUi.show) {
      option = _options.loadingUi.option || DEFAUT_OPTION;
      if (_options.loadingUi.target) {
        option.target = _options.loadingUi.target;
      }
      // 显示loading
      // 每个请求拥有一个loading实例
      _options.instance = yufp.util.globalVm.$loading(option);
    }
    // 添加逻辑处理url 中+号特殊字符
    if (_options.url) {
      _options.url = _options.url.replace(/\+/g, '%2B');
    }
    _options.url = _this.getUrl(_options);

    var deferred = new yufp.core.Deferred();
    var event = {
      data: _options.data,
      requestUrl: _options.url
    };
    // before过滤
    if (_this._doFilter(0, event) === false) {
      event.code = event.code ? event.code : 2;
      deferred.reject(event.code, event.message, event.data);
      if (_options.callback) {
        _options.callback(event.code, event.message, event.data);
      }
      return deferred;
    }
    _options.data = event.data.data;
    _options.headers = yufp.extend({}, event.data.headers || {}, _options.headers, this.getExtendHeader());
    if (_options.needToken) {
      var token = _this.getToken();
      if (!token) {
        // 若token不存在，表示会话过期，终止请求
        yufp.logger.warn('Yufp.Service: Session expiration request termination');
        return deferred;
      }
      _options.headers[_this.tokenId] = 'Bearer ' + token;
    }
    _options.type = options.method;
    _options.async = options.async;
    _options.success = function (data, status, xhr) {
      // -------------------------------- recorder 模式 -----------------------------------------
      if (yufp.settings.recorderModel && yufp.settings.recorderScope.indexOf('yufp.service') != -1) {
        yufp.logger.info('[service receive]  url:' + _options.url + ' ,response:' + JSON.stringify(data));
      }
      // -------------------------------- recorder 模式 -----------------------------------------
      // 加延迟才可观察到loading的效果
      setTimeout(function () {
        // 关闭loading
        _options.instance && _options.instance.close();
      }, _this.timeout);
      // 定义过滤事件
      var successEvent = { code: 0, message: 'success', data: data};
      successEvent = window.YUFP_SYS_CONFIG.multiLanguage ? _this.deepTraverseMsg(successEvent) : successEvent;
      // after过滤器
      // 过滤器中断调用处理
      if (_this._doFilter(1, successEvent, event) === false) {
        var code = successEvent.code ? successEvent.code : 1;
        // 通知调用失败
        deferred.reject(code, successEvent.message, successEvent.data);
        if (_options.callback) {
          _options.callback(code, successEvent.message, successEvent.data);
        }
        return;
      }
      // 通知调用成功
      deferred.resolve(successEvent.code, successEvent.message, successEvent.data);
      if (_options.callback) {
        _options.callback(successEvent.code, successEvent.message, successEvent.data);
      }
    };
    _options.error = function (xhr, status) {
      var msg = xhr.responseText;
      msg = !msg ? status : msg;
      // 加延迟才可观察到loading的效果
      setTimeout(function () {
        // 关闭loading
        _options.instance && _options.instance.close();
      }, _this.timeout);
      // 定义过滤事件
      var errorEvent = { code: 1, message: msg, xhr: xhr, requestUrl: _options.url};
      // 处理消息翻译
      errorEvent = window.YUFP_SYS_CONFIG.multiLanguage ? _this.deepTraverseMsg(errorEvent) : errorEvent;
      // exception过滤
      if (_this._doFilter(2, errorEvent, event) === false) {
        // 通知调用失败
        deferred.reject(errorEvent.code, errorEvent.message, errorEvent.data);
        return;
      }

      errorEvent.code = errorEvent.code ? errorEvent.code : 1;
      // 通知调用失败
      deferred.reject(errorEvent.code, errorEvent.message, errorEvent.data);
      // 判断是否存在回调函数
      if (_options.callback) {
        _options.callback(errorEvent.code, errorEvent.message, errorEvent.data);
      }
    };
    yufp.core.ajax(_options);
  };
  /**
   * @desc 二层翻译 返回层中的message数据
   * @param {Object} res：response数据
   */
  Service.prototype.deepTraverseMsg = function (res) {
    var _this = this;
    if ((res.message || res.msg) && res.code) {
      res[res.message ? 'message' : 'msg'] = _this.handleMsg(res) || res.message || res.msg || '';
    }
    if (res.data && res.data.code) {
      _this.deepTraverseMsg(res.data);
    }
    return res;
  };
  /**
   * @desc 处理消息语言翻译并返回信息
   * @param {Object} data 返回消息内容中data
   *
   */
  Service.prototype.handleMsg = function (data) {
    var code = data.code,
      message = data.message || data.msg,
      i = 0,
      countMsg = 0,
      transalteMsg = '',
      res = {};
    // code是否存在多个
    if (code && String(code).indexOf('|') != -1) {
      code = code.split('|');
      message = message.split('|');
      for (var len = code.length; i < len; ++i) {
        var curCode = String(code[i]).replace(/(^\s*)|(\s*$)/g, '');
        res = yufp.language.getLocaleText('message.' + curCode, data.i18nData, countMsg) || message[i] || '';
        transalteMsg += res.temp + (i === (len - 1) ? '' : ' | ');
        countMsg = res.count;
      }
    } else {
      transalteMsg = yufp.language.getLocaleText('message.' + code, data.i18nData) || message;
    }
    return transalteMsg;
  };

  /**
   * 获取最终访问的完整URL
   * @param param {url }
   * @returns {string}
   */
  Service.prototype.getUrl = function (param) {
    var paramUrl = param.url || param.name;
    if (!paramUrl) {
      throw new Error('Yufp.service.request: 未设置请求URL');
    }
    var reg = /^(http|https):\/\//;
    // url请求未附带http(s)://前缀，则按yufp.settings.url及ssl添加前缀
    if (!reg.test(paramUrl)) {
      var protocol, prefixUrl = yufp.settings.url || '';
      // yufp.settings.url 非空，即非默认同源模式，计算服务端URL源路径
      if (prefixUrl) {
        protocol = reg.test(prefixUrl) ? '' : yufp.settings.ssl ? 'https://' : 'http://';
        prefixUrl = protocol + prefixUrl;
      }
      paramUrl = ('/' + paramUrl).replace(/^\/\//, '/'); // 添加前缀
      paramUrl = (this.basePath || '') + paramUrl; // 添加basePath
      paramUrl = prefixUrl + paramUrl; // 组合origin
    }
    return paramUrl;
  };

  /**
   * 存储token信息
   * @param {object|string} token 对象
   * { access_token: '', refresh_token: '', expires_in: '' }
   */
  Service.prototype.putToken = function (tokenObj) {
    if (typeof tokenObj == 'object') {
      var currentTime = new Date().getTime(); // 当前时间
      // 记录 access_token 时间（相对于浏览器客户端来说），默认减去1min中
      tokenObj.buildTime = currentTime - 60000; // 单位：毫秒
    }
    this.storage.put('UFP-' + this.tokenId, tokenObj);
  };

  /**
   * 获取token信息，可能会触发refreshToken方法
   * refresh_token无效时，access_token返回空串
   */
  Service.prototype.getToken = function () {
    var _this = this;
    var tokenObj = this.storage.get('UFP-' + this.tokenId) || '';
    var currentTime = new Date().getTime(); // 当前时间
    if (tokenObj.expires_in && (currentTime - tokenObj.buildTime) / 1000 > tokenObj.expires_in) {
      // access_token 已失效，通过refresh_token 同步ajax请求重新获取；
      tokenObj = _this.refreshToken(tokenObj);
      if (tokenObj) {
        _this.putToken(tokenObj);
      }
      return tokenObj ? tokenObj.access_token : '';
    } else {
      // access_token 未失效，正常获取使用
      return tokenObj.access_token;
    }
  };

  /**
   * 移除token信息
   */
  Service.prototype.removeToken = function () {
    this.storage.remove('UFP-' + this.tokenId);
  };

  /**
   * 通过refresh_token，同步ajax请求重新获取相关token信息
   * @param {object|string} token 对象
   * { access_token: '', refresh_token: '', expires_in: '' }
   */
  Service.prototype.refreshToken = function (tokenObj) {
    var returnTokenObj;
    yufp.service.request({
      needToken: false,
      async: false, // 同步请求
      url: backend.uaaService + '/oauth/token',
      method: 'post',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'Authorization': 'Basic d2ViX2FwcDo='
      },
      data: {
        'grant_type': 'refresh_token',
        'refresh_token': tokenObj.refresh_token
      },
      callback: function (code, message, response) {
        if (response && response.access_token) {
          // 刷新相关token请求成功
          returnTokenObj = {
            'access_token': response.access_token,
            'refresh_token': response.refresh_token,
            'expires_in': response.expires_in
          };
        } else {
          // 刷新相关token请求失败, 跳转至登录页
          yufp.session.logout(true);
        }
      }
    });
    return returnTokenObj;
  };

  /**
   * 添加服务请求过滤器
   * @param {*} obj 过滤器对象
   */
  Service.prototype.addFilter = function (obj, unshift) {
    if (typeof obj != 'object') {
      yufp.logger.error('filter args must been json object');
      return;
    }
    if (!obj.name) {
      yufp.logger.error('filter args must have name attribute');
      return;
    }
    if (!obj.before || typeof obj.before !== 'function') {
      yufp.logger.error('filter args must have before function');
      return;
    }
    if (!obj.after || typeof obj.after !== 'function') {
      yufp.logger.error('filter args must have after function');
      return;
    }
    if (!obj.exception || typeof obj.exception !== 'function') {
      yufp.logger.error('filter args must have exception function');
      return;
    }
    unshift ? this._filters.unshift(obj) : this._filters.push(obj);
  };

  /**
   * 移除服务请求过滤器
   * @param {*} obj 过滤器对象
   */
  Service.prototype.removeFilter = function (obj) {
    var name = typeof obj == 'string' ? obj : obj.name;
    var i = 0;
    for (; i < this._filters.length; i++) {
      if (name == this._filters[i].name) {
        break;
      }
    }
    if (i < this._filters.length) {
      this._filters.splice(i, 1);
    }
  };

  /**
   * 执行过滤
   * @param {*} type 过滤类型
   * @param {*} event 过滤事件参数
   */
  Service.prototype._doFilter = function (type, event, oldEvent) {
    var fname = 'exception';
    fname = type == 0 ? 'before' : fname;
    fname = type == 1 ? 'after' : fname;
    for (var i = 0; i < this._filters.length; i++) {
      if (!this._filters[i][fname]) {
        continue;
      }
      var res = this._filters[i][fname](event, oldEvent);
      if (res === false) {
        return false;
      }
    }
  };

  return new Service();
}));
